home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / strategy / xshisen-.001 / xshisen-~ / xshisen-1.35 / body.C < prev    next >
C/C++ Source or Header  |  1996-01-25  |  26KB  |  1,053 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include "body.h"
  4.  
  5. void
  6. PiePos::Delete(const Point &p1, const Point &p2)
  7. {
  8.     int diff = 0;
  9. #if DEBUG
  10.     fprintf(stderr, "Piepos::Delete ");
  11.     for(int xx=0; xx<count; xx++)
  12.         fprintf(stderr, "(%d,%d)", p[xx].x, p[xx].y);
  13.     fprintf(stderr, "\n");
  14. #endif
  15.     for(int i=0; i<count; i++) {
  16.         if (diff)
  17.             p[i-diff] = p[i];
  18.         if (p[i]==p1 || p[i]==p2)
  19.             diff++;
  20.     }
  21. #if DEBUG
  22.     if (diff != 2)
  23.         fprintf(stderr, "!!! Delete: No match (%d,%d)(%d,%d)\n",p1.x,p1.y,p2.x,p2.y);
  24. #endif
  25.     if (diff)
  26.         count -= 2;
  27. }
  28.  
  29. void
  30. PiePos::Move(const Point &from, const Point &to)
  31. {
  32.     for(int i=0; i<count; i++) {
  33.         if (p[i]==from)
  34.             p[i] = to;
  35.     }
  36. }
  37.  
  38. Body::Body(int g, int x, int y, Widget parent, Widget top)
  39.     : History(x*y/2), game(g), xsize(x), ysize(y)
  40. {
  41.     int i, num_each;
  42.  
  43.     pie      = new (Mahjong** [xsize]);
  44.     initialp = new (Mahjong** [xsize]);
  45.     pstatus  = new (unsigned char* [xsize]);
  46.     for(i=0; i<xsize; i++) {
  47.         pie[i]      = new (Mahjong* [ysize]);
  48.         initialp[i] = new (Mahjong* [ysize]);
  49.         pstatus[i]  = new unsigned char [ysize];
  50.     }
  51.     num_each = x*y/PKIND;
  52.     for(i=0; i<PKIND; i++) {
  53.         piepos[i] = new PiePos(num_each);
  54.     }
  55.     clearqueue = 0;
  56.     hintNum    = 0;
  57.     pause      = 0;
  58.     if (game >= NUM_GAME*2)
  59.         gravity = 1;
  60.     else
  61.         gravity = 0;
  62. #if USE_MOTIF
  63.     body = XtVaCreateManagedWidget("drawing", xmDrawingAreaWidgetClass, parent,
  64.                                    XmNtopAttachment,    XmATTACH_WIDGET,
  65.                                    XmNrightAttachment,  XmATTACH_FORM,
  66.                                    XmNleftAttachment,   XmATTACH_FORM,
  67.                                    XmNbottomAttachment, XmATTACH_FORM,
  68.                                    XmNtopWidget,        top,
  69.                                    XmNwidth,            globRes.Width,
  70.                                    XmNheight,           globRes.Height,
  71.                                    NULL);
  72.     XtAddCallback(body, XmNexposeCallback, (XtCallbackProc)ExposeCB, NULL);
  73.     XtAddCallback(body, XmNresizeCallback, (XtCallbackProc)ResizeCB, NULL);
  74. #else /* USE_MOTIF */
  75.     body = XtVaCreateManagedWidget("simple", simpleWidgetClass, parent,
  76.                                    XtNfromVert,    top,
  77.                                    XtNtop,         XawChainTop,
  78.                                    XtNbottom,      XawRubber,
  79.                                    XtNleft,        XawRubber,
  80.                                    XtNright,       XawRubber,
  81.                                    XtNwidth,       globRes.Width,
  82.                                    XtNheight,      globRes.Height,
  83.                                    XtNborderWidth, 0,
  84.                                    XtNresizable,   True,
  85.                                    NULL);
  86.     XtAddEventHandler(body, ExposureMask, False,
  87.                       (XtEventHandler)ExposeCB, NULL);
  88.     XtAddEventHandler(body, ConfigureNotify, False,
  89.                       (XtEventHandler)ResizeCB, NULL);
  90. #endif /* USE_MOTIF */
  91. }
  92.  
  93. void
  94. Body::SetGC(void)
  95. {
  96.     Colormap cmap = XDefaultColormapOfScreen(XtScreen(body));
  97.     XColor  c1;
  98.     XGCValues gcv;
  99.  
  100.     gcv.line_width = globRes.connLineWidth;
  101.     gcv.foreground = globRes.connLineColor;
  102.     gcv.join_style = JoinRound;
  103.     gcl = XCreateGC(XtDisplay(body), XtWindow(body),
  104.                     GCForeground | GCLineWidth | GCJoinStyle, &gcv);
  105.     XtVaGetValues(body, XtNbackground, &(c1.pixel), NULL);
  106.     gcv.foreground = c1.pixel;
  107.     gcc = XCreateGC(XtDisplay(body), XtWindow(body),
  108.                     GCLineWidth | GCForeground | GCJoinStyle, &gcv);
  109. }
  110.  
  111. Body::~Body(void)
  112. {
  113.     XFreeGC(XtDisplay(body), gcl);
  114.     XFreeGC(XtDisplay(body), gcc);
  115.     for(int i=0; i<ysize; i++) {
  116.         delete[] pie[i];
  117.         delete[] initialp[i];
  118.         delete[] pstatus[i];
  119.     }
  120.     for(int j=0; j<PKIND; j++) {
  121.         delete piepos[j];
  122.     }
  123.     delete[] pie;
  124.     delete[] initialp;
  125.     delete[] pstatus;
  126.     XtDestroyWidget(body);
  127. }
  128.  
  129. void
  130. Body::ChangeGame(int g, int x, int y)
  131. {
  132.     int i, num_each;
  133.  
  134.     xsize = x;
  135.     ysize = y;
  136.     game  = g;
  137.     for(i=0; i<ysize; i++) {
  138.         delete[] pie[i];
  139.         delete[] initialp[i];
  140.         delete[] pstatus[i];
  141.     }
  142.     for(i=0; i<PKIND; i++) {
  143.         delete piepos[i];
  144.     }
  145.     delete[] pie;
  146.     delete[] initialp;
  147.     delete[] pstatus;
  148.  
  149.     pie      = new (Mahjong** [xsize]);
  150.     initialp = new (Mahjong** [xsize]);
  151.     pstatus  = new (unsigned char* [xsize]);
  152.     for(i=0; i<xsize; i++) {
  153.         pie[i]      = new (Mahjong* [ysize]);
  154.         initialp[i] = new (Mahjong* [ysize]);
  155.         pstatus[i]  = new unsigned char [ysize];
  156.     }
  157.     num_each = x*y/PKIND;
  158.     for(i=0; i<PKIND; i++) {
  159.         piepos[i] = new PiePos(num_each);
  160.     }
  161.     ChangeHistorySize(xsize*ysize/2);
  162. }
  163.  
  164. int
  165. Body::reset(int value)
  166. {
  167.     int i, j;
  168.     for(i=0; i<xsize; i++)
  169.         for(j=0; j<ysize; j++)
  170.             pstatus[i][j] = value;
  171.     for(i=0; i<PKIND; i++)
  172.         piepos[i]->Clear();
  173.     for(i=0; i<xsize; i++)
  174.         for(j=0; j<ysize; j++)
  175.             piepos[pie[i][j]->id]->Add(Point(i, j));
  176.     refreshhint();
  177.     ResetHistory();
  178.     if (hintNum < 5)
  179.         return -1;  // This configuration may be problematic
  180.     else
  181.         return 0;   // Good initial configuration!
  182. }
  183.  
  184. int
  185. Body::can_pass(int i, int j)
  186. {
  187.     if (i<-1 || i>xsize || j<-1 || j>ysize)
  188.         return 0;
  189.     else if (i==-1 || i==xsize)
  190.         return 1;
  191.     else if (j==-1 || j==ysize)
  192.         return 1;
  193.     else if (pstatus[i][j]==0)
  194.         return 1;
  195.     else if (i==xp1.x && j==xp1.y)
  196.         return 1;
  197.     else if (i==xp2.x && j==xp2.y)
  198.         return 1;
  199.     else
  200.         return 0;
  201. }
  202.  
  203. void
  204. Body::get_hrange(int i, int j, int &is, int &ie)
  205. {
  206.     is = ie = i;
  207.     while(can_pass(is-1, j)) is--;
  208.     while(can_pass(ie+1, j)) ie++;
  209. }
  210.  
  211. void
  212. Body::get_vrange(int i, int j, int &js, int &je)
  213. {
  214.     js = je = j;
  215.     while(can_pass(i, js-1)) js--;
  216.     while(can_pass(i, je+1)) je++;
  217. }
  218.  
  219. void
  220. Body::refreshhint(void)
  221. {
  222.     Point (*p)[2], *t;
  223.     int   c = 0, dummy, num;
  224.     int   max_c;
  225.  
  226.     max_c = xsize*ysize*(xsize*ysize/PKIND - 1)/2;
  227.     p = new (Point [max_c][2]);
  228.     t = new Point[xsize*ysize/PKIND];
  229.  
  230.     if (hintNum == 0)
  231.         delete[] hintArray;
  232.     for(int i=0; i<PKIND; i++) {
  233.         piepos[i]->GetPosArray(t, num);
  234.         for(int j=0; j<num; j++)
  235.             for(int k=j+1; k<num; k++)
  236.                 if (pstatus[t[j].x][t[j].y] == 1 &&
  237.                     pstatus[t[k].x][t[k].y] == 1) {
  238.                     xp1 = t[j];
  239.                     xp2 = t[k];
  240.                     if ((sweep_vert(t[j], t[k], dummy) ||
  241.                          sweep_horiz(t[j], t[k], dummy))) {
  242.                         p[c][0] = t[j];
  243.                         p[c][1] = t[k];
  244.                         c++;
  245.                     }
  246.                 }
  247.     }
  248. #if DEBUG
  249.     fprintf(stderr, "Removalbe pairs: %d\n",c);
  250. #endif
  251.     hintNum = c;
  252.     currentHintNum = 0;
  253.     if (c != 0) {
  254.         hintArray = new Point [c*2];
  255.         memcpy(hintArray, p, c*2*sizeof(Point));
  256.     }
  257.     delete[] p;
  258.     delete[] t;
  259. }
  260.  
  261. void
  262. Body::getnexthint(void)
  263. {
  264.     hint_p1 = hintArray[currentHintNum*2];
  265.     hint_p2 = hintArray[currentHintNum*2+1];
  266.     currentHintNum++;
  267.     if (currentHintNum >= hintNum)
  268.         currentHintNum = 0;
  269. }
  270.  
  271. void
  272. Body::fallpiece(int col)
  273. {
  274.     int j, j0;
  275.     int flag = 0;
  276.  
  277.     for(j0=ysize-1; j0>=0; j0--) {
  278.         if (pstatus[col][j0] != 1)
  279.             break;
  280.     }
  281.     // At this point, j0 is the lowest empty piece in the specified
  282.     // column.  This means that the pieces existing above here must
  283.     // be felt downto here.
  284.     for(j=j0-1; j>=0; j--) {
  285.         if (pstatus[col][j] == 1) {
  286.             unsigned char c;
  287.             Mahjong *m;
  288.             c = pstatus[col][j];
  289.             m = pie[col][j];
  290.             pstatus[col][j]  = pstatus[col][j0];
  291.             pie[col][j]      = pie[col][j0];
  292.             pstatus[col][j0] = c;
  293.             pie[col][j0]     = m;
  294.             piepos[m->id]->Move(Point(col, j), Point(col, j0));
  295.             j0--;
  296.             flag = 1;
  297.         }
  298.     }
  299.     /* if (flag)
  300.         DrawCol(col); */
  301. }
  302.  
  303. void
  304. Body::insertpiece(const Point &p)
  305. {
  306.     int j, j0;
  307.  
  308.     if (pstatus[p.x][p.y] == 1) {
  309.         for(j0=p.y; j0>=0; j0--) {
  310.             if (pstatus[p.x][j0] != 1)
  311.                 break;
  312.         }
  313.         // At this point, j0 is the lowest empty place.
  314.         for(j=j0+1; j<=p.y; j++) {
  315.             unsigned char c;
  316.             Mahjong *m;
  317.             c = pstatus[p.x][j];
  318.             m = pie[p.x][j];
  319.             pstatus[p.x][j]  = pstatus[p.x][j0];
  320.             pie[p.x][j]      = pie[p.x][j0];
  321.             pstatus[p.x][j0] = c;
  322.             pie[p.x][j0]     = m;
  323.             piepos[m->id]->Move(Point(p.x, j), Point(p.x, j0));
  324.             j0++;
  325.         }
  326.     }
  327.     pstatus[p.x][p.y] = 1;
  328.     piepos[pie[p.x][p.y]->id]->Add(p);
  329.     DrawCol(p.x);
  330. }
  331.  
  332. void
  333. Body::removePair(void)
  334. {
  335.     AddHistory(xp1, xp2, vp1, vp2);
  336.     rest -= 2;
  337.     pstatus[xp1.x][xp1.y] = 0;
  338.     pstatus[xp2.x][xp2.y] = 0;
  339.     clearqueue++;
  340.     LinkLine();
  341.     piepos[pie[xp1.x][xp1.y]->id]->Delete(xp1, xp2);
  342.     if (gravity) {
  343.         fallpiece(xp1.x);
  344.         if (xp1.x != xp2.x)
  345.             fallpiece(xp2.x);
  346.     }
  347.     refreshhint();
  348.     ResetTimer();
  349.     status = 0;
  350. }
  351.  
  352. int
  353. Body::GetRest(void)
  354. {
  355.     return rest;
  356. }
  357.  
  358. void
  359. Body::SetGeometry(int width, int height)
  360. {
  361. #if DEBUG
  362.     fprintf(stderr, "SetGeometry(%d,%d)\n", width, height);
  363. #endif
  364.     XtVaSetValues(toplevel,
  365.                   XtNallowShellResize, True,
  366.                   NULL);
  367.     XtVaSetValues(body,
  368.                   XtNwidth,  (Dimension)width,
  369.                   XtNheight, (Dimension)height,
  370.                   NULL);
  371.     XtVaSetValues(toplevel,
  372.                   XtNallowShellResize, False,
  373.                   NULL);
  374.     SetSize(width, height);
  375. }
  376.  
  377. // This returns 1 if the widget size is changed
  378. int
  379. Body::GetGeometry(int &width, int &height)
  380. {
  381.     Dimension w, h;
  382.     XtVaGetValues(body,
  383.                   XtNwidth,  &w,
  384.                   XtNheight, &h,
  385.                   NULL);
  386.     width  = w;
  387.     height = h;
  388.     if (width != currentWidth || height != currentHeight)
  389.         return 1;
  390.     else
  391.         return 0;
  392. }
  393.  
  394. void
  395. Body::SetSize(int x, int y)
  396. {
  397. #if DEBUG
  398.     fprintf(stderr, "SetSize(%d,%d)\n",x,y);
  399. #endif
  400.     // This function must be called after realized!
  401.     Cursor cursor = XCreateFontCursor(XtDisplay(body), XC_watch);
  402.     XDefineCursor(XtDisplay(body), XtWindow(body), cursor);
  403.     xstep = x / (2+xsize);
  404.     ystep = y / (2+ysize);
  405.     xmarg = XMARGIN;
  406.     ymarg = YMARGIN;
  407.     xoff  = (x - xstep * xsize) / 2;
  408.     yoff  = (y - ystep * ysize) / 2;
  409.     currentWidth  = x;
  410.     currentHeight = y;
  411.     for(int i=0; i<PKIND; i++)
  412.         Mp[i].Resize(toplevel, gcl, xstep-xmarg*2, ystep-ymarg*2);
  413.     XClearArea(XtDisplay(body), XtWindow(body), 0, 0, x, y, True);
  414.     XUndefineCursor(XtDisplay(body), XtWindow(body));
  415. }
  416.  
  417. void
  418. Body::Sort(void)
  419. {
  420.     int num_each = xsize*ysize/PKIND;
  421.     int c = 0;
  422.  
  423.     for(int d=0; d<ysize/4; d++) {
  424.         for(int i=0; i<xsize; i++) {
  425.             for(int j=0; j<4; j++) {
  426.                 pie[i][d*4+j] = &Mp[c/num_each];
  427.                 c++;
  428.             }
  429.         }
  430.     }
  431.     rest = xsize*ysize;
  432.     status = 3;
  433.     reset(1);
  434. }
  435.  
  436. // Sort function for "click trial"
  437. void
  438. Body::Sort2(void)
  439. {
  440.     int num_each, num_block, basex, basey;
  441.     int blockx, blocky;
  442.     int x1, y1, x2, y2;
  443.  
  444.     num_each  = xsize*ysize/PKIND;
  445.     num_block = num_each / 2;
  446.     if (xsize%num_block == 0) {
  447.         blockx = xsize / num_block;
  448.         blocky = ysize;
  449.     } else {
  450.         blockx = xsize * 2 / num_block;
  451.         blocky = ysize / 2;
  452.     }
  453.     for(int i=0; i<num_block; i++) {
  454.         basex = (i * blockx) % xsize;
  455.         basey = ysize * i / blocky / num_block;
  456.         basey *= blocky;
  457.         for(int j=0; j<PKIND; j++) {
  458.             x1 = basex + j/blocky;
  459.             y1 = basey + j%blocky;
  460.             x2 = basex + blockx - 1 - j/blocky;
  461.             y2 = basey + blocky - 1 - j%blocky;
  462.             pie[x1][y1] = &Mp[j];
  463.             pie[x2][y2] = &Mp[j];
  464.         }
  465.     }
  466.     rest = xsize*ysize;
  467.     status = 0;
  468.     clearqueue = 0;
  469.     if (demoMode)
  470.         helpUsed = 1;  // Never be a high score!
  471.     else
  472.         helpUsed = 0;
  473.     reset(1);
  474. }
  475.  
  476. void
  477. Body::Restart(void)
  478. {
  479.     for(int ky=0; ky<ysize; ky++)
  480.         for(int kx=0; kx<xsize; kx++)
  481.             pie[kx][ky] = initialp[kx][ky];
  482.     rest = xsize*ysize;
  483.     status = 0;
  484.     clearqueue = 0;
  485.     helpUsed = 1;
  486.     reset(1);
  487. }
  488.  
  489. void
  490. Body::Shuffle(void)
  491. {
  492.     int  i, a1, a2, b1, b2;
  493.     Mahjong *p;
  494.     int num_shuffle = xsize*ysize*2;
  495.  
  496.     // Check if current game is "Click Trial"
  497.     if (game / NUM_GAME == 1) {
  498.         Sort2();
  499.         goto done;
  500.     }
  501.     // Loop until the good initial configuration found
  502.     while(1) {
  503.         for(i=0; i<num_shuffle; i++) {
  504. #if HAVE_DRAND48
  505.             a1 = (int)(drand48() * xsize);
  506.             b1 = (int)(drand48() * ysize);
  507.             a2 = (int)(drand48() * xsize);
  508.             b2 = (int)(drand48() * ysize);
  509. #elif HAVE_RANDOM
  510.             a1 = random() % xsize;
  511.             b1 = random() % ysize;
  512.             a2 = random() % xsize;
  513.             b2 = random() % ysize;
  514. #elif HAVE_RAND
  515.             a1 = (rand()>>2) % xsize;
  516.             b1 = (rand()>>3) % ysize;
  517.             a2 = (rand()>>4) % xsize;
  518.             b2 = (rand()>>5) % ysize;
  519. #else
  520.             This line will cause error because all the random number
  521.             generating functions are not available!
  522. #endif
  523.             p = pie[a1][b1];
  524.             pie[a1][b1] = pie[a2][b2];
  525.             pie[a2][b2] = p;
  526.         }
  527.         rest = xsize*ysize;
  528.         status = 0;
  529.         clearqueue = 0;
  530.         if (demoMode)
  531.             helpUsed = 1;  // Never be a high score!
  532.         else
  533.             helpUsed = 0;
  534.         if (reset(1) == 0) {
  535.             break;
  536.         }
  537.     }
  538.   done:
  539.     initialHintNum = hintNum;
  540.     for(int ky=0; ky<ysize; ky++)
  541.         for(int kx=0; kx<xsize; kx++)
  542.             initialp[kx][ky] = pie[kx][ky];
  543. }
  544.  
  545. void
  546. Body::DrawOne(int i, int j)
  547. {
  548.     if (pstatus[i][j] == 1 && !pause)
  549.         pie[i][j]->Draw(body, gcl, i*xstep+xoff+xmarg, j*ystep+yoff+ymarg, 1);
  550.     else if (pstatus[i][j] == 2 && !pause)
  551.         pie[i][j]->Draw(body, gcl, i*xstep+xoff+xmarg, j*ystep+yoff+ymarg, 2);
  552.     else
  553.         XClearArea(XtDisplay(body), XtWindow(body),
  554.                    i*xstep+xoff+xmarg, j*ystep+yoff+ymarg,
  555.                    xstep, ystep, False);
  556. }
  557.  
  558. void
  559. Body::DrawCol(int i)
  560. {
  561.     XClearArea(XtDisplay(body), XtWindow(body), i*xstep+xoff+xmarg, yoff+ymarg,
  562.                xstep, ystep*ysize, False);
  563.     for(int j=0; j<ysize; j++)
  564.         DrawOne(i, j);
  565. }
  566.  
  567. void
  568. Body::DrawAll(void)
  569. {
  570.     XClearArea(XtDisplay(body), XtWindow(body), 0, 0,
  571.                xoff+xstep*(2+xsize), yoff+ystep*(2+ysize), False);
  572.     for(int i=0; i<xsize; i++)
  573.         for(int j=0; j<ysize; j++)
  574.             DrawOne(i, j);
  575. }
  576.  
  577. void
  578. Body::GetPos(int x, int y, int &i, int &j)
  579. {
  580.     i = x-xoff-xmarg;
  581.     if (i<0) i = -1;
  582.     else i /= xstep;
  583.     j = y-yoff-ymarg;
  584.     if (j<0) j = -1;
  585.     else j /= ystep;
  586. }
  587.  
  588. void
  589. Body::DrawRegion(int x, int y, int w, int h)
  590. {
  591.     int is, js, ie, je;
  592.     GetPos(x, y, is, js);
  593.     GetPos(x+w, y+h, ie, je);
  594.  
  595.     for(int i=is; i<=ie; i++)
  596.         for(int j=js; j<=je; j++)
  597.             if (i>=0 && i<xsize && j>=0 && j<ysize)
  598.                 DrawOne(i, j);
  599. }
  600.  
  601. int
  602. Body::sweep_horiz(Point p1, Point p2, int &ir)
  603. // p1 and p2 must not be reference because this function may swap these values.
  604. {
  605.     int i1, j1, i2, j2;
  606.     int is1, ie1, is2, ie2;
  607.     int is, ie, i, j;
  608.     int value = 1000;  // let it enough big (smaller value is better)
  609.  
  610.     if (p1.y > p2.y) {  // make always p1.y<p2.y
  611.         Point pp = p1;
  612.         p1 = p2;
  613.         p2 = pp;
  614.     }
  615.     i1 = p1.x;
  616.     j1 = p1.y;
  617.     i2 = p2.x;
  618.     j2 = p2.y;
  619.     get_hrange(i1, j1, is1, ie1);
  620.     get_hrange(i2, j2, is2, ie2);
  621.     is = (is1 > is2) ? is1 : is2;
  622.     ie = (ie1 < ie2) ? ie1 : ie2;
  623.     for(i=is; i<=ie; i++) {
  624.         int flag = 1;
  625.         for(j=j1; j<=j2; j++)
  626.             if (!can_pass(i, j)) {
  627.                 flag = 0;
  628.                 break;
  629.             }
  630.         if (flag==1) { // ÄµéΩéΘ!
  631.             int this_value = abs(i-i1) + abs(i-i2);
  632.             if (this_value < value) {
  633.                 value = this_value;
  634.                 ir = i;
  635.             }
  636.         }
  637.     }
  638.     if (value < 1000)
  639.         return 1;
  640.     else
  641.         return 0;
  642. }
  643.  
  644. int
  645. Body::sweep_vert(Point p1, Point p2, int &jr)
  646. // p1 and p2 must not be reference because this function may swap these values.
  647. {
  648.     int i1, j1, i2, j2;
  649.     int js1, je1, js2, je2;
  650.     int js, je, i, j;
  651.     int value = 1000;  // let it enough big (smaller value is better)
  652.  
  653.     if (p1.x > p2.x) {  // make always p1.x<p2.x
  654.         Point pp = p1;
  655.         p1 = p2;
  656.         p2 = pp;
  657.     }
  658.     i1 = p1.x;
  659.     j1 = p1.y;
  660.     i2 = p2.x;
  661.     j2 = p2.y;
  662.     get_vrange(i1, j1, js1, je1);
  663.     get_vrange(i2, j2, js2, je2);
  664.     js = (js1 > js2) ? js1 : js2;
  665.     je = (je1 < je2) ? je1 : je2;
  666.     for(j=js; j<=je; j++) {
  667.         int flag = 1;
  668.         for(i=i1; i<=i2; i++)
  669.             if (!can_pass(i, j)) {
  670.                 flag = 0;
  671.                 break;
  672.             }
  673.         if (flag==1) { // ÄµéΩéΘ!
  674.             int this_value = abs(j-j1) + abs(j-j2);
  675.             if (this_value < value) {
  676.                 value = this_value;
  677.                 jr = j;
  678.             }
  679.         }
  680.     }
  681.     if (value < 1000)
  682.         return 1;
  683.     else
  684.         return 0;
  685. }
  686.  
  687. // (i1,j1) é╞ (i2,j2) é╠ægé▌ìçéφé╣é¬üuĵéΩéΘüvé⌐é╟éñé⌐üAâ`âFâbâNé╖éΘ
  688. int
  689. Body::Check(const Point &p1, const Point &p2)
  690. {
  691.     int ir, jr;
  692.  
  693.     xp1 = p1;
  694.     xp2 = p2;
  695.     if (p1==p2 || pie[p1.x][p1.y] != pie[p2.x][p2.y])
  696.         return 0;
  697.     if (sweep_vert(p1, p2, jr)) {
  698.         vp1 = p1;
  699.         vp2 = p2;
  700.         vp1.y = vp2.y = jr;
  701.         return 1;
  702.     }
  703.     else if (sweep_horiz(p1, p2, ir)) {
  704.         vp1 = p1;
  705.         vp2 = p2;
  706.         vp1.x = vp2.x = ir;
  707.         return 1;
  708.     }
  709.     else
  710.         return 0;
  711. }
  712.  
  713. void
  714. Body::GetPiece(int x, int y)
  715. {
  716.     int   xi, yi;
  717.     Point here_p;
  718.  
  719. #if DEBUG
  720.     if (x < 10 && !demoMode) {
  721.         rest = 0;
  722.         return;
  723.     }
  724. #endif
  725.     GetPos(x, y, xi, yi);
  726.     if (xi<0 || xi>=xsize || yi<0 || yi>=ysize)
  727.         return;
  728.     here_p = Point(xi, yi);
  729.     switch(status) {
  730.     case 0: // First piece
  731.         if (pstatus[xi][yi] == 1) {
  732.             // button1 is clicked as first piece
  733.             status = 1;
  734.             clicked_p = here_p;
  735.             pstatus[xi][yi] = 2;
  736.             DrawOne(xi, yi);
  737.         }
  738.         break;
  739.     case 1: // Second piece
  740.         if (pstatus[xi][yi] != 1)  // Avoid to get zombie piece!
  741.             break;
  742.         if (Check(here_p, clicked_p)) {
  743.             // It can be removed!
  744.             pstatus[xi][yi] = 2;
  745.             DrawOne(xi, yi);
  746.             removePair();
  747.                 // No parameters because it uses xp1, xp2,
  748.                 // vp1 and vp2 member variables.
  749.         }
  750.         break;
  751.     case 4:  // After hint
  752.         Check(hint_p1, hint_p2);  // Just to get vp1 and vp2
  753.         removePair();
  754.         break;
  755.     }
  756. }
  757.  
  758. void
  759. Body::CancelPiece(int x, int y)
  760. {
  761.     int xi, yi;
  762.  
  763.     GetPos(x, y, xi, yi);
  764.     if (xi<0 || xi>=xsize || yi<0 || yi>=ysize)
  765.         return;
  766.     switch(status) {
  767.     case 1:  // Cancel (button3)
  768.         status = 0;
  769.         pstatus[clicked_p.x][clicked_p.y] = 1;
  770.         DrawOne(clicked_p.x, clicked_p.y);
  771.         break;
  772.     case 4:  // Cancel after hint
  773.         status = 0;
  774.         pstatus[hint_p1.x][hint_p1.y] = 1;
  775.         pstatus[hint_p2.x][hint_p2.y] = 1;
  776.         DrawOne(hint_p1.x, hint_p1.y);
  777.         DrawOne(hint_p2.x, hint_p2.y);
  778.         break;
  779.     }
  780. }
  781.  
  782. void
  783. Body::Back(void)
  784. {
  785.     Point b1, b2;
  786.  
  787.     // Don't back from initial state
  788.     if (rest == xsize*ysize)
  789.         return;
  790.     // At first, clear the all lines existing
  791.     ClearLineAll();
  792.     GetXY(-1, b1, b2);
  793.     if (BackHistory()) {
  794.         rest +=2;
  795.         if (gravity) {
  796.             if (b1.y < b2.y) {
  797.                 // This order is very important here. The piece at
  798.                 // the lower position must be inserted first.
  799.                 insertpiece(b2);
  800.                 insertpiece(b1);
  801.             } else {
  802.                 insertpiece(b1);
  803.                 insertpiece(b2);
  804.             }
  805.         } else {
  806.             piepos[pie[b1.x][b1.y]->id]->Add(b1);
  807.             piepos[pie[b1.x][b1.y]->id]->Add(b2);
  808.             pstatus[b1.x][b1.y] = 1;
  809.             pstatus[b2.x][b2.y] = 1;
  810.             DrawOne(b1.x, b1.y);
  811.             DrawOne(b2.x, b2.y);
  812.         }
  813.         refreshhint();
  814.     }
  815. }
  816.  
  817. int
  818. Body::Active(void)
  819. {
  820.     if (status != 3 && pause == 0)
  821.         return 1;
  822.     else
  823.         return 0;
  824. }
  825.  
  826. void
  827. Body::HourlyPatrol(void)
  828. {
  829.     if (clearqueue > 0 && GetTimer()>=globRes.connLineTime)
  830.         ClearLine();
  831.     if (rest == 0) {
  832.         char b[128];
  833.         long result;
  834.  
  835.         sc->SetScore(result = tm->GetTimer(), game);
  836.         sprintf(b, globRes.timeFormat, result/60000, (result/1000)%60);
  837.         if (helpUsed) {
  838.             if (!globRes.autoDemo)
  839.                 sc->LogRecord(2, result, game, initialHintNum, 0);
  840.             Message(MESSAGE_SYMBOL, b, timeOut, PopDownTO);
  841.         }
  842.         else {
  843.             if (!globRes.autoDemo)
  844.                 sc->LogRecord(1, result, game, initialHintNum, 0);
  845.             Message(MESSAGE_SYMBOL, b, timeOut, PopDownTO,
  846.                     (XtCallbackProc)ScoreRegisterCB);
  847.         }
  848.         GameOver();
  849.     }
  850.     else if (hintNum == 0) {
  851.         if (!globRes.autoDemo)
  852.             sc->LogRecord(3, tm->GetTimer(), game, initialHintNum, rest);
  853.         Message(MESSAGE_SYMBOL, globRes.tedumari, timeOut, PopDownTO);
  854.         GameOver();
  855.     }
  856. }
  857.  
  858. void
  859. Body::GameOver(void)
  860. {
  861.     ClearLineAll();
  862.     status = 3;
  863.     mb->Insensitive();
  864. }
  865.  
  866. void
  867. Body::LogGiveUp(void)  // Log the time even you give up the previous game!
  868. {
  869.     if (status != 3) {
  870.         long result = tm->GetTimer();
  871.         if (!globRes.autoDemo)
  872.             sc->LogRecord(0, result, game, initialHintNum, rest);
  873.     }
  874. }
  875.  
  876. void
  877. Body::SetDemo(int demo)
  878. {
  879.     if (demo) {
  880.         timeOut  = 5000;
  881.         demoMode = 1;
  882.     } else {
  883.         timeOut  = 0;
  884.         demoMode = 0;
  885.     }
  886. }
  887.  
  888. void
  889. Body::Robot(void)
  890. {
  891.     if (hintNum > 0 && clearqueue == 0 && rest !=0) {
  892.         Hint();
  893.         GetPiece(xoff+xstep/2, yoff+ystep/2);
  894.     }
  895. }
  896.  
  897. void
  898. Body::LinkLine(void)
  899. {
  900.     Point np1, np2;
  901.     int ti1, ti2, tj1, tj2;
  902.     int vi1, vi2, vj1, vj2;
  903.     XPoint pts[4];
  904.  
  905.     GetXY(0 - clearqueue, np1, np2);
  906.     ti1 = np1.x; tj1 = np1.y; ti2 = np2.x; tj2 = np2.y;
  907.     GetV(0 - clearqueue, np1, np2);
  908.     vi1 = np1.x; vj1 = np1.y; vi2 = np2.x; vj2 = np2.y;
  909.     pts[0].x = xoff+xmarg+ti1*xstep+xstep/2;
  910.     pts[0].y = yoff+ymarg+tj1*ystep+ystep/2;
  911.     pts[1].x = xoff+xmarg+vi1*xstep+xstep/2;
  912.     pts[1].y = yoff+ymarg+vj1*ystep+ystep/2;
  913.     pts[2].x = xoff+xmarg+vi2*xstep+xstep/2;
  914.     pts[2].y = yoff+ymarg+vj2*ystep+ystep/2;
  915.     pts[3].x = xoff+xmarg+ti2*xstep+xstep/2;
  916.     pts[3].y = yoff+ymarg+tj2*ystep+ystep/2;
  917.     XDrawLines(XtDisplay(body), XtWindow(body), gcl, pts, 4, CoordModeOrigin);
  918. }
  919.  
  920. void
  921. Body::ClearLine(void)
  922. {
  923.     Point np1, np2;
  924.     int ti1, ti2, tj1, tj2;
  925.     int vi1, vi2, vj1, vj2;
  926.     XPoint pts[4];
  927.  
  928.     GetXY(0 - clearqueue, np1, np2);
  929.     ti1 = np1.x; tj1 = np1.y; ti2 = np2.x; tj2 = np2.y;
  930.     GetV(0 - clearqueue, np1, np2);
  931.     vi1 = np1.x; vj1 = np1.y; vi2 = np2.x; vj2 = np2.y;
  932.     pts[0].x = xoff+xmarg+ti1*xstep+xstep/2;
  933.     pts[0].y = yoff+ymarg+tj1*ystep+ystep/2;
  934.     pts[1].x = xoff+xmarg+vi1*xstep+xstep/2;
  935.     pts[1].y = yoff+ymarg+vj1*ystep+ystep/2;
  936.     pts[2].x = xoff+xmarg+vi2*xstep+xstep/2;
  937.     pts[2].y = yoff+ymarg+vj2*ystep+ystep/2;
  938.     pts[3].x = xoff+xmarg+ti2*xstep+xstep/2;
  939.     pts[3].y = yoff+ymarg+tj2*ystep+ystep/2;
  940.     XDrawLines(XtDisplay(body), XtWindow(body), gcc, pts, 4, CoordModeOrigin);
  941.     if (gravity) {
  942.         DrawCol(ti1);
  943.         if (ti1 != ti2)
  944.             DrawCol(ti2);
  945.     } else {
  946.         DrawOne(ti1, tj1);
  947.         DrawOne(ti2, tj2);
  948.     }
  949.     clearqueue--;
  950. }
  951.  
  952. void
  953. Body::ClearLineAll(void)
  954. {
  955.     while(clearqueue > 0)
  956.         ClearLine();
  957. }
  958.  
  959. void
  960. Body::Hint(void)
  961. {
  962.     if (status == 4) {
  963.         status = 0;
  964.         pstatus[hint_p1.x][hint_p1.y] = 1;
  965.         pstatus[hint_p2.x][hint_p2.y] = 1;
  966.         DrawOne(hint_p1.x, hint_p1.y);
  967.         DrawOne(hint_p2.x, hint_p2.y);
  968.     }
  969.     else if (status == 1) {
  970.         status = 0;
  971.         pstatus[clicked_p.x][clicked_p.y] = 1;
  972.         DrawOne(clicked_p.x, clicked_p.y);
  973.     }
  974.     getnexthint();
  975.     helpUsed = 1;
  976.  
  977.     pstatus[hint_p1.x][hint_p1.y] = 2;
  978.     pstatus[hint_p2.x][hint_p2.y] = 2;
  979.     DrawOne(hint_p1.x, hint_p1.y);
  980.     DrawOne(hint_p2.x, hint_p2.y);
  981.     status = 4;
  982. }
  983.  
  984. int
  985. Body::TogglePause(void)
  986. {
  987.     if (status == 3) // Pause at no game is problematic
  988.         return -1;
  989.     if (pause == 0) {
  990.         pause = 1;
  991.     } else if (pause == 1) {
  992.         pause = 0;
  993.     }
  994.     DrawAll();
  995.     return pause;
  996. }
  997.  
  998. void
  999. Body::ToggleClickTrial(void)
  1000. {
  1001.     if (game / NUM_GAME != 1) {
  1002.         game = game % NUM_GAME + NUM_GAME;
  1003.         mb->ClickTrial(True, False);
  1004.     } else {
  1005.         game %= NUM_GAME;
  1006.         mb->ClickTrial(False, False);
  1007.     }
  1008.     gravity = 0;
  1009. }
  1010.  
  1011. void
  1012. Body::ToggleGravity(void)
  1013. {
  1014.     if (game / NUM_GAME != 2) {
  1015.         game = game % NUM_GAME + NUM_GAME*2;
  1016.         mb->ClickTrial(False, True);
  1017.         gravity = 1;
  1018.     } else {
  1019.         game %= NUM_GAME;
  1020.         mb->ClickTrial(False, False);
  1021.         gravity = 0;
  1022.     }
  1023. }
  1024.  
  1025. void
  1026. Body::WriteRcFile(void)
  1027. {
  1028.     FILE *file;
  1029.     const char *tr, *gr;
  1030.  
  1031.     file = fopen(rcfile, "w");
  1032.     if (file) {
  1033.         fprintf(file, CLASS_NAME "*gameSize: %d\n", game%NUM_GAME);
  1034.         switch(game / NUM_GAME) {
  1035.         case 1: // Click Trial
  1036.             tr = "true";
  1037.             gr = "false";
  1038.             break;
  1039.         case 2: // Gravity
  1040.             tr = "false";
  1041.             gr = "true";
  1042.             break;
  1043.         default: // Normal
  1044.             tr = "false";
  1045.             gr = "false";
  1046.             break;
  1047.         }
  1048.         fprintf(file, CLASS_NAME "*trialMode: %s\n", tr);
  1049.         fprintf(file, CLASS_NAME "*gravityMode: %s\n", gr);
  1050.         fclose(file);
  1051.     }
  1052. }
  1053.